import Url from '@ohos.url';
import { UIAbility } from '@kit.AbilityKit';

/**
 * 页面路由打开模式
 */
export enum PageRouteOpenMode {
  /**
   * push打开
   */
  push,
  /**
   * replace打开
   */
  replace,
}

/**
 * 页面路由打开策略
 */
export enum RouterStrategy {
  /**
   * 优先NavPathStack打开页面。只有当NavPathStack无法响应时，才尝试用router打开页面。
   */
  navigationFirst,
  /**
   * 优先用router打开页面。只有当router无法响应时，才尝试NavPathStack打开页面。
   */
  routerFirst,
  /**
   * 只用NavPathStack打开页面。
   */
  navigationOnly,
  /**
   * 只用router打开页面。
   */
  routerOnly,
}

/**
 * 页面路由返回值处理策略
 */
export enum RouterResultStrategy {
  /**
   * 在被打开的页面pop出栈时，触发打开该页面对应的回调方法。
   */
  onPagePop,
  /**
   * 返回指定页面routeName时，当routeName onShow时，触发最后获取到的回调方法（即routeName打开页面时传入的回调方法）。
   */
  onPageShow,
}

/**
 * 页面返回参数
 */
export interface RouterBackOptions {
  /**
   * 返回到指定页面
   */
  url?: string;

  /**
   * 携带的参数
   */
  params?: object;
  /**
   * 只支持navigationOnly/routerOnly/undefined三种传值。
   *
   * 若为undefined，默认取RouterManager逻辑（先执行navigation逻辑，失败则执行router逻辑）
   */
  routerStrategy?: RouterStrategy;

}

/**
 * RouterBackOptions包装类，为了字面量传值，interface不能直接增加方法，所以组件内部会对RouterBackOptions进行包装处理。
 */
export class RouterBackOptionsWrapper {
  /**
   * 外部传入的RouterBackOptions
   */
  rawOptions: RouterBackOptions

  /**
   * 经过处理的参数，包含RouterBackOptions中`url`和`params`中的参数。
   */
  params: Record<string, any> = {}
  /**
   * path列表
   */
  paths: string[] = []
  /**
   * 模块名，path的第一段。
   */
  moduleName: string = ''
  /**
   * 判断是命名路由还是页面路径。传入的url的第一段为`pages/`则认为是页面路径。
   */
  isRouterPath: boolean = false
  /**
   * 路由名称，剔除了moduleName后的path。若是页面路径，则等于path。
   */
  routeName: string = ''

  constructor(options: RouterBackOptions) {
    this.rawOptions = options

    let backParams: Record<string, Object> = {}
    if (options.params) {
      let paramsKeys = Object.keys(options.params)
      for (let keysElement of paramsKeys) {
        backParams[keysElement] = options.params[keysElement]
      }
    }

    if (options.url && options.url.length > 0) {
      let path = options.url
      if (!path.includes('://')) {
        path = "scheme://host/" + path
      }
      const urlObject = Url.URL.parseURL(path);

      let routePath: string = urlObject.pathname.slice(1)
      this.paths = routePath.split("/")
      this.routeName = routePath;
      if (this.paths.length > 1) {
        this.routeName = this.paths.slice(1).join('/')
        if (this.paths[0] === 'pages') {
          this.isRouterPath = true
          this.routeName = routePath
        }
      }

      if (path.includes('?')) {
        const urlObject = Url.URL.parseURL(path);
        urlObject.params.forEach((value, name, searchParams) => {
          console.log(name, value, urlObject.params === searchParams);
          backParams[name] = value
        });
      }
    }
    this.params = backParams
  }
}

/**
 * 路由注册参数。
 */
export class RouteRegisterOptions {
  /**
   * 路由名
   */
  routeName: string
  /**
   * 是否包含参数。目前只有Navigation模式使用。
   */
  hasParams?: boolean
}

/**
 * 路由处理器接口。多种路由实现方案需要实现该接口。
 */
export interface RouterHandler {
  /**
   * 初始化操作。
   * 可选实现。
   * @param uiAbility 在EntryAbility方法中初始化，传入ability对象。
   */
  init?(uiAbility: UIAbility)

  /**
   * 打开路由。
   * @param request 请求参数。经过包装处理的对象。
   * @returns 路由的返回值
   */
  open(request: RouterRequestWrapper): Promise<RouterResponse>

  /**
   * 路由返回
   * @description 不支持uri带参数的key和params的key相同，否则uri会覆盖params参数
   * @param options
   * @returns 关闭页面是否成功
   */
  close?(options?: RouterBackOptionsWrapper): boolean
}

/**
 * 路由请求对象
 */
export interface RouterRequest {
  /**
   * 路由名称。如果包含url参数，则会覆盖`params`中的同名参数。
   */
  url: string
  /**
   * 参数。
   */
  params?: Record<string, any>
  /**
   * 页面路由打开方式。
   */
  openMode?: PageRouteOpenMode
  /**
   * 打开路由所在的页面对象。有些路由需要知道是哪个页面在调用我。
   */
  pageInstance?: ESObject
  /**
   * 页面策略，若为undefined，默认取RouterManager全局逻辑
   */
  routerStrategy?: RouterStrategy
}

/**
 * 路由请求对象包装类。为了字面量传值，interface不能直接增加方法，所以组件内部会对RouterRequest进行包装处理。
 */
export class RouterRequestWrapper {
  /**
   * 路由传入的RouterRequest对象
   */
  rawRequest: RouterRequest
  /**
   * router页面路由使用。打开当前的路由的页面Index。
   */
  fromIndex?: number

  /**
   * 打开路由获取返回值的回调函数
   */
  resolve?: (value: RouterResponse | PromiseLike<RouterResponse>) => void

  /**
   * 经过处理的参数，包含RouterBackOptions中`url`和`params`中的参数。
   */
  params: Record<string, any>
  /**
   * 经过解析后获得的pathname，首字符不为/
   */
  uri?: string
  /**
   * path对象列表
   */
  paths: string[]
  /**
   * 模块名，path的第一段。
   */
  moduleName: string
  /**
   * 判断是命名路由还是页面路径。传入的url的第一段为`pages/`则认为是页面路径。
   */
  isRouterPath: boolean
  /**
   * 路由名称，剔除了moduleName后的path。若是页面路径，则等于path。
   */
  routeName: string

  constructor(request: RouterRequest, fromIndex?: number) {
    this.rawRequest = request;
    this.fromIndex = fromIndex

    let path = request.url
    if (!path.includes('://')) {
      path = "scheme://host/" + path
    }
    const urlObject = Url.URL.parseURL(path);
    let params = request.params ? request.params : new Map();
    if (Array.from(urlObject.params.keys()).length > 0) {
      urlObject.params.forEach((value, name, searchParams) => {
        params![name] = decodeURIComponent(value)
      });
    }

    this.params = params
    this.uri = urlObject.pathname.slice(1) //移除开头的/

    let routePath: string = this.uri ?? ''
    this.paths = routePath.split("/")
    this.moduleName = this.paths[0]

    this.isRouterPath = false
    this.routeName = routePath;
    if (this.paths.length > 1) {
      this.routeName = this.paths.slice(1).join('/')
      if (this.paths[0] === 'pages') {
        this.isRouterPath = true
        this.routeName = routePath
      }
    }
  }
}

/**
 * 路由返回值错误对象。
 */
export class RouterResponseError {
  code: number
  msg: string

  static Success: RouterResponseError = {
    code: 200,
    msg: '成功'
  }

  static RequestInterrupt: RouterResponseError = {
    code: 300,
    msg: '请求被拦截'
  }

  static RequestFallbackError: RouterResponseError = {
    code: 301,
    msg: '请求fallback逻辑异常'
  }

  static RequestNotFoundResponsor: RouterResponseError = {
    code: 400,
    msg: '找不到响应者'
  }

  static URLFormatError: RouterResponseError = {
    code: 5001,
    msg: '路由地址格式有误'
  }
  static DynamicImportError: RouterResponseError = {
    code: 5002,
    msg: '动态导入错误'
  }
  static UnknownError: RouterResponseError = {
    code: 9999,
    msg: '未知错误'
  }
}

/**
 * 路由返回对象。
 */
export interface RouterResponse {
  /**
   * 代码
   */
  code: number
  /**
   * 和code对应的描述信息。
   */
  msg: string
  /**
   * 具体的返回数据。
   */
  data?: any
}